home *** CD-ROM | disk | FTP | other *** search
- /* Listing 2. */
-
- /***************************************************
- *
- * Module Name:
- * daa - dynamic array allocator
- *
- * Description:
- * this dynamic array allocator is designed to be
- * efficient, i.e., it uses only one valloc() for
- * the entire array, and flexible. It can allocate
- * arrays of up to 10 dimensions of any type that
- * will return a size with the sizeof "C" operator.
- * it is also very efficient from the point of
- * view of array access. the single valloc()
- * ensures locality of reference that eliminates
- * excess paging encountered with dynamic array
- * allocation schemes that use multiple malloc()'s.
- * Unless the array is larger than a full page
- * it will be contained entirely on one page.
- * It can allocate arrays of structure, enum or
- * union type. A corresponding free(free(ptr))
- * of the allocated area must normally be done
- * (unless you want to allocate to program ter-
- * mination). The sixth parameter returns a
- * pointer to do a free on. do not free on the
- * function return pointer since arrays of non-
- * zero subscripted first dimensions will not
- * point to the allocated space, but some offset
- * based on the subscript offset of the first
- * dimension. The array is initialized to the
- * value pointed to by the last parameter, or
- * not initialized if NULL. the last parameter
- * pointer should point to something with a size
- * the same as the size of the type in the sizeof
- * first argument. arrays may be allocated to
- * have one or more dimensions with non-zero
- * integer(+ or -) start subscripts. thus,
- * arrays may be one based or zero based or
- * any based for that matter.
- *
- * parameters:
- * size - size of the basic array data
- * object, this will usually be
- * passed from the sizeof() operator
- * in the call
- *
- * no_dim - number of array dimensions
- *
- * dimensions - a single dimensional array of
- * the dimensions of the array to
- * be allocated
- *
- * start - a single dimensional array of
- * integer start subscripts for each
- * corresponding dimension of the
- * dimensions array, may be negative
- *
- * err_code - pointer to returned error code
- * value
- *
- * free_ptr - pointer to the base pointer of
- * the vallocated array space
- * for the caller to free
- *
- * init_ptr - initialization pointer parameter
- * (NULL if no initialization is
- * desired).
- *
- * returns:
- * a pointer to char that points to the start of
- * the dynamically allocated array area. this
- * will normally need to be cast to the type of
- * the subsequent array references. routine
- * failure will return NULL.
- *
- * examples:
- * char *fptr;
- *
- * allocate 3 dimensional 3x3x3 zeroed int array
- * all zero based:
- * int ***array;
- * int init = 0;
- * unsigned d[3] = {3,3,3};
- * int st[3] = {0,0,0};
- * array = (int ***)
- * daa(sizeof(int), 3, d, st, &err_code,
- * &fptr, &init);
- * array[0][2][1] = 1; assign int
- * free(fptr);
- *
- * allocate 2 dimensional 2x3 double array
- * initialized to 1.0 and one based:
- * double **array;
- * double init = 1.0;
- * unsigned d[2] = {2,3};
- * int st[2] = {1,1};
- * array = (double ***)
- * daa(sizeof(double), 2, d, st, &err_code,
- * &fptr, &init);
- * array[1][2] = 1.5; assign double
- * free(fptr);
- *
- * allocate 3 dimensional 4x3x2 array of structures
- * initialized to the s_init structure and the
- * first index zero based with the second index five
- * based and the third index -2 based:
- * struct s {
- * int i;
- * double d;
- * };
- * struct s s_init = {5, 2.5};
- * struct s ***array;
- * unsigned d[3] = {4,3,2};
- * int st[3] = {0,5,-2};
- * array = (struct s ***)
- * daa(sizeof(struct s), 3, d, st, &err_code,
- * &fptr, &s_init);
- * array[1][5][-2].i = 1; assign first element
- * array[3][6][-2].d = 1.5; assign 2nd element
- * free(fptr);
- *
- * errors:
- * error free operation returns 0 in *err_code.
- * any of the following errors will result in a
- * NULL pointer return and *err_code set to the
- * error number.
- * 1. number of dimensions must be > 0 and <= 10
- * 2. size must be greater than 1
- * 3. no dimension may be zero
- * 4. memory must be successfully allocated
- * (valloc() != NULL)
- *
- * failure to index the subscripts in the manner
- * established by the starting index array will
- * of course result in run time errors. this is
- * not an array allocation error but an array
- * usage error, similar to any array access on a
- * static "C" zero based array outside the normal
- * 0...n-1 bounds.
- *
- ****************************************************
- */
- #include <stdio.h>
-
- #define MAX_DIM 10 /* max no. of array dimensions */
-
- /* these variables are used in the recursive
- pointer setup routines */
- static unsigned long data_size; /* data unit size*/
- static unsigned long num_dim; /* # of dimensions */
- /* dimensions of array */
- static unsigned long dim[MAX_DIM];
- /* product of dimensions from 0 to
- index, dim[0]*dim[1]...dim[index] */
- static unsigned long dp[MAX_DIM];
- /* start index of array dimensions */
- static int st[MAX_DIM];
- /* size of pointer */
- static unsigned long ptr_size = sizeof(char *);
- /* points to base of allocated array */
- static char *base;
-
- char *daa(size, no_dim, dimensions,
- start, err_code, free_ptr, init_ptr)
- unsigned size;
- unsigned no_dim;
- unsigned dimensions[];
- int start[];
- unsigned *err_code;
- char **free_ptr;
- char *init_ptr;
- {
- /* offset in pointer words of first data byte */
- unsigned long data_off;
- /* array of current dimension indices */
- unsigned long dim_ind[MAX_DIM];
- unsigned long i,j;
- char *p_data, /* pointer to array data */
- *p; /* tmp pointer */
-
- char *al();
- unsigned long doff();
- unsigned long off();
-
- *err_code = 0;
- if (no_dim < 1 || no_dim > MAX_DIM){
- *err_code = 1;
- return NULL;
- }
-
- if (size < 1){
- *err_code = 2;
- return NULL;
- }
-
- num_dim = no_dim;
-
- /* set dim_ind to all zeros, the multiple invocations
- * of the recursive array allocation routine al()
- * will pass changed by 1 dim_ind arrays to each
- * invocation of al(). set dim[] and dp[] from
- * dimensions[] input array and st[] from start[]
- * input array */
- dp[0] = dimensions[0];
- for (i = 0;i < num_dim;i++){
- dim_ind[i] = 0;
- if (dimensions[i] == 0){
- *err_code = 3;
- return NULL;
- }
- dim[i] = dimensions[i];
- if (i > 0){
- dp[i] = dp[i-1]*dimensions[i];
- }
- st[i] = start[i];
- }
-
- data_size = size;
-
- /* allocate enough memory for the data plus
- all the array pointers */
- if ((base = (char *)
- valloc((data_off = off(num_dim-1))*ptr_size +
- dp[num_dim-1]*data_size)) == NULL){
- *err_code = 4;
- return NULL;
- }
-
- /* return allocated space pointer that caller
- * should use to free space */
- *free_ptr = base;
-
- /* if init_ptr is NULL skip initialization */
- if (init_ptr != NULL){
- /* set p_data to point to the start of
- the data area */
- p_data = base + data_off*ptr_size;
-
- /* initialize the array */
- for (i = 0;i < dp[num_dim-1];i++){
- p = init_ptr;
- for (j = 0;j < data_size;j++){
- *p_data++ = *p++;
- }
- }
- }
-
- /* do array setup i.e. all the pointer stuff */
- return al(0, dim_ind);
- }
-
- static char *
- al(level, dim_ind)
- unsigned long level;
- unsigned long dim_ind[];
- {
- char **ptrs;
- unsigned long i;
- if (level < num_dim - 1){
- ptrs = (char **) (base + off(level)*ptr_size +
- ((level == 0)?0:doff(level, dim_ind,
- dp[level])*ptr_size));
- for (i = 0;i < dim[level];i++){
- dim_ind[level] = i;
- ptrs[i] = al(level+1, dim_ind) -
- st[level+1]*((level+1 == num_dim-1) ?
- data_size:ptr_size);
- }
- if (level == 0){
- ptrs -= st[0];
- }
- } else {
- ptrs = (char **) (base + off(level)*ptr_size +
- doff(level, dim_ind, dp[level])
- *data_size - ((level == 0) ?
- (st[0]*data_size):0));
- }
- return (char *) ptrs;
- }
-
- static unsigned long
- doff(level, dim_ind, dim_prod)
- unsigned long level;
- unsigned long dim_ind[];
- unsigned long dim_prod;
- {
- if (level == 0){
- return 0;
- } else {
- return doff(level-1, dim_ind, dim_prod) +
- (dim_prod/dp[level-1])*dim_ind[level-1];
- }
- }
-
- static unsigned long
- off(level)
- unsigned long level;
- {
- if (level == 0){
- return 0;
- } else {
- return dp[level-1] + off(level-1);
- }
- }
-